

#   核心是高性能的 ndarray（N维数组）对象


import numpy as np

arr = np.arange(6)
new_arr = arr.reshape(2, 3)
print(new_arr)

print(arr.reshape(2, 3, order=""))



# 副本 (Copy) 与视图 (View):


# 视图(View) ：视图是原始数组数据的另一种访问方式，共享相同的数据缓冲区
# 内存模型：视图对象拥有自己的元数据（形状、步长等），但数据指针指向原始数组的内存
# 特点：

# 修改视图会影响原始数组
# 创建速度快，不占用额外内存（仅需要存储新元数据）
# 典型操作：切片、转置、reshape、改变dtype（某些情况）



# 副本(Copy)：完全独立的新数组，拥有自己的数据缓冲区  .copy()
# 内存模型：副本对象拥有完全独立的内存空间和数据

# 特点：
# 修改副本不会影响原始数组
# 创建速度慢，占用额外内存（需要复制全部数据）
# 典型操作：显式调用copy()、花式索引、某些计算操作

# 判断：arr.base is None 通常表示 arr 是副本（拥有数据）；否则可能是视图。


import numpy as np

arr = np.arange(12).reshape(3, 4)
print("原始数组:\n", arr)

# 切片创建视图
view1 = arr[1:, :3]  # 行1到最后，列0到2
view1[0, 0] = 100    # 修改视图

print("\n修改视图后的原始数组:")
print(arr)  # 可以看到原始数组被修改


view3 = arr.reshape(4, 3)
view3[0, 0] = 300
print("\nreshape视图修改后的原始数组:")
print(arr)  # 原始数组被修改



view2 = arr.T  # 转置是视图
view2[0, 1] = 200
print("\n转置视图修改后的原始数组:")
print(arr)  # 原始数组相应位置被修改





copy1 = arr.copy()  # 显式创建副本
copy1[0, 0] = 999
print("\n修改副本后的原始数组:")
print(arr)  # 原始数组不受影响

copy2 = arr[[0, 2], :]  # 花式索引创建副本
copy2[0, 0] = 888
print("\n花式索引后的原始数组:")
print(arr)  # 原始数组不受影响

copy3 = arr * 2  # 算术运算创建副本
copy3[0, 0] = 777
print("\n计算操作后的原始数组:")
print(arr)  # 原始数组不受影响







# -----------------------------判断机制与底层原理-----------------------------
def check_view_or_copy(a):
    if a.base is None:
        print("这是一个副本（拥有自己的数据）")
    else:
        print("这是一个视图（共享数据）")
        print("基础对象是:", a.base)

arr = np.arange(6)
view = arr[1:4]
copy = arr.copy()

check_view_or_copy(view)  # 这是一个视图
check_view_or_copy(copy)  # 这是一个副本

# OWNDATA：False表示视图，True表示副本
# C_CONTIGUOUS：内存布局信息




















# 结构化数组是NumPy中处理表格化异构数据的强大工具，它允许在单个数组中存储不同类型的数据，同时保持NumPy的高效计算特性

# 可以定义包含多种数据类型的结构
# 通过字段名而非仅索引访问数据
# 保持NumPy数组的高效内存布局  ----  字段连续或元素连续
# 支持对字段的批量操作


import numpy as np

# 定义数据类型
dt = np.dtype([
    ('name', 'U10'),  # Unicode字符串，长度10
    ('age', 'i4'),    # 32位整数
    ('weight', 'f4'), # 32位浮点数
    ('height', 'f4')  # 32位浮点数
])

# 创建结构化数组
people = np.array([
    ('Alice', 25, 55.5, 165.2),
    ('Bob', 30, 75.1, 180.3),
    ('Cathy', 28, 62.0, 170.5)
], dtype=dt)

print(people)



# 从字典定义dtype（NumPy 1.14+）
dt = np.dtype({
    'names': ['name', 'age', 'weight', 'height'],
    'formats': ['U10', 'i4', 'f4', 'f4'],
    'offsets': [0, 40, 44, 48],  # 显式指定字节偏移
    'itemsize': 52                # 总字节大小
})


# 从pandas DataFrame转换
import pandas as pd
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Cathy'],
    'age': [25, 30, 28],
    'weight': [55.5, 75.1, 62.0]
})
struct_array = df.to_records(index=False)








# ----------------------------性能优化深度指南--------------------------------------

# NumPy 的底层是用 C 实现的，向量化操作可以避免 Python 解释器的开销
# 向量化操作：使用 ufunc 和内置函数
# 低效的循环
result = np.zeros(len(arr))
for i in range(len(arr)):
    result[i] = arr[i] * 2 + 1

# 高效的向量化操作
result = arr * 2 + 1  # 使用 ufunc 的广播机制

# 使用 np.where 代替条件循环
mask = arr > 0.5
result = np.where(mask, arr * 2, arr / 2)




# 广播通过避免实际复制数据来节省内存
# 低效的显式扩展
a = np.random.rand(1000, 1)
b = np.tile(a, (1, 1000))  # 实际复制数据

# 高效的广播
b = a * np.random.rand(1, 1000)  # 无数据复制

# 复杂广播示例
# 计算每对元素的差值 (1000x1000) 矩阵
arr = np.random.rand(1000)
diff = arr[:, np.newaxis] - arr[np.newaxis, :]  # 使用广播而非双重循环






# 视图 (view) 共享原始数组的数据缓冲区
# 副本 (copy) 需要分配新内存并复制数据
# 使用 np.may_share_memory() 检查数组是否共享内存
# 避免链式索引 arr[a][b] 而使用 arr[a, b] 以减少副本
# 使用 np.ascontiguousarray 确保内存连续布局
arr = np.arange(1e6)  # 大数组

# 检测是否是视图
def is_view(a, b):
    return a.base is b or b.base is a

# 创建视图而非副本
view = arr[::2]  # 步长切片创建视图
copy = arr[::2].copy()  # 显式创建副本

# reshape 通常创建视图
reshaped = arr.reshape(1000, 1000)  # 视图











#  数据类型 (dtype) 优化
# 更小的数据类型减少内存占用和带宽需求
# CPU 对某些数据类型有优化指令（如 SSE/AVX 对 float32）
# 使用 np.can_cast() 检查类型转换安全性
# 考虑 np.result_type() 预测操作结果类型
# 默认 float64 可能不是最优的
arr = np.random.rand(1000, 1000)  # float64
arr_float32 = np.random.rand(1000, 1000).astype(np.float32)  # 减少50%内存

# 使用最小足够的整数类型
small_ints = np.arange(100, dtype=np.int8)  # 节省内存

# 复合数据类型优化
dt = np.dtype([('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
coords = np.zeros(1000, dtype=dt)  # 紧凑存储



# 类型提升与内存优化
def safe_convert(arr1, arr2):
    # 计算公共类型并创建新数组
    common_dtype = np.promote_types(arr1.dtype, arr2.dtype)
    arr1_new = arr1.astype(common_dtype)  # 安全转换
    arr2_new = arr2.astype(common_dtype)
    return arr1_new, arr2_new

arr1 = np.array([1, 2, 3], dtype=np.int16)
arr2 = np.array([1.5, 2.5, 3.5], dtype=np.float32)
result = safe_convert(arr1, arr2)
print(result[0].dtype)  # float64


import numpy as np

# 场景：根据输入动态选择输出类型
def auto_cast(data, target_type):
    if np.can_cast(data, target_type, casting='safe'):
        return data.astype(target_type)
    else:
        promoted_type = np.promote_types(data.dtype, target_type)
        print(f"自动提升类型: {promoted_type}")
        return data.astype(promoted_type)

# 测试用例
data_int = np.array([100, 200], dtype=np.int32)
target_float = np.float32

result = auto_cast(data_int, target_float)
print(result.dtype)  # float32（int32 → float32 安全）

data_large = np.array([1e100], dtype=np.float64)
target_float32 = np.float32
result = auto_cast(data_large, target_float32)  # 触发类型提升至 float64







# 避免中间数组分配可以减少内存分配开销
# 预分配输出数组可以更好地控制内存布局
# 使用 np.ufunc.at 进行无缓冲的原地操作
# 结合 np.multiply.accumulate 等特殊方法
# 常规操作创建多个临时数组
result = np.sqrt(arr**2 + arr.mean())

# 使用 out 参数优化
out = np.empty_like(arr)
np.square(arr, out=out)
np.add(out, np.mean(arr), out=out)
np.sqrt(out, out=out)

# 原地操作
arr *= 2  # 原地乘法
np.add(arr, 1, out=arr)  # 显式原地操作








# ---------------------------------高级加速工具--------------------------------

# numexpr 优化
import numexpr as ne

# 复杂表达式优化
arr = np.random.rand(1e6)
result = ne.evaluate("sin(arr) + log(arr) * 3")  # 自动多线程优化

# 指定输出
out = np.empty_like(arr)
ne.evaluate("arr**2 + arr**3", out=out)